package com.ld.shieldsb.common.web.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jsoup.Jsoup;

import com.alibaba.fastjson.JSONObject;
import com.ld.shieldsb.common.composition.util.web.Global;
import com.ld.shieldsb.common.core.util.StringUtils;
import com.ld.shieldsb.common.core.util.date.DateUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * web相关操作
 * 
 * @ClassName WebUtil
 * @author <a href="mailto:donggongai@126.com" target="_blank">kevin</a>
 * @date 2016年8月25日 下午2:02:02
 *
 */
@Slf4j
public class WebUtil {
    protected static final String FORWORD = "forward:"; // 转发
    protected static final String REDIRECT = "redirect:"; // 重定向
    protected static final Pattern PATTERN_IPFROM_CHINAZ = Pattern.compile("您的IP ([\\W\\w]+) 来自");
    protected static final Pattern PATTERN_IPFROM_11315 = Pattern.compile("您的IP为：([\\W\\w]+?) ：");
    protected static final Pattern PATTERN_IPFROM_IP138 = Pattern.compile("您的IP地址是：\\[(.+?)\\] 来自：");

    /**
     * 
     * 获取请求的IP地址
     * 
     * @Title getIpAddr
     * @param request
     * @return String
     */
    public static String getIpAddr(HttpServletRequest request) {
        String defaultIP = "127.0.0.1";
        String ip = defaultIP;
        try {
            defaultIP = request.getRemoteAddr();
            // 针对于nginx多级反向代理情况
            ip = request.getHeader("nkforwardfor"); // 可伪造，需要在nginx中设置：proxy_set_header nkforwardfor $proxy_add_x_forwarded_for;
            if (ipIsCanDeal(ip)) {
                String[] ipStrs = ip.split(",");
                for (String ipStr : ipStrs) {
                    if (!"unknown".equalsIgnoreCase(ipStr)) { // 取第一个不为unknown的值
                        ip = ipStr;
                        break;
                    }
                }
                String ipWl = request.getHeader("WL-Proxy-Client-IP"); // 其中“WL” 就是 WebLogic
                if (ipWl != null && ipWl.length() != 0 && !"unknown".equalsIgnoreCase(ipWl) && !ipWl.equals(ip)) { // 优先取
                    log.info("ip异常:" + ip + " != (wl)" + ipWl);
                    ip = ipWl;
                }
            } else {
                // 针对于nginx反向代理情况
                ip = request.getHeader("nkrealip"); // 可伪造，需要在nginx中设置：proxy_set_header nkrealip $remote_addr;
                // 针对于正常情况
                if (!ipIsCanDeal(ip)) {
                    ip = defaultIP;
                }
            }
        } catch (Exception e) {
            log.warn("", e);
        }
        if (!ipIsLegal(ip)) {
            ip = defaultIP;
        }
        return ip;
    }

    /**
     * 判断ip是否可以解析
     * 
     * @author lv
     * @param ip
     * @return
     */
    private static boolean ipIsCanDeal(String ip) {
        return ip != null && ip.length() > 0 && !"unknown".equalsIgnoreCase(ip);
    }

    /**
     * 判断ip是否合法
     * 
     * @author lv
     * @param ip
     * @return
     */
    private static boolean ipIsLegal(String ip) {
        // ipv6未严格判断
        return ip.matches("\\d+\\.\\d+\\.\\d+\\.\\d+") || (ip.contains(":") && !ip.matches(".*?[\\s，,\\.].*?"));
    }

    /**
     * 
     * 下载文件,可以直接使用basicService中的downFile(file)方法
     * 
     * @Title download
     * @param downFileName
     *            文件名
     * @param file
     *            文件
     * @param response
     * @return
     * @throws IOException
     *             boolean
     */
    public static boolean download(String downFileName, File file, HttpServletResponse response) throws IOException {
        if (file != null) {
            // 如果文件名没有扩展名，则根据路径添加
            if (!downFileName.contains(".")) {
                String filePath = file.getName();
                downFileName += filePath.substring(filePath.lastIndexOf("."));
            }
            response.reset();
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.setHeader("Content-Disposition",
                    "attachment; filename=\"" + new String(downFileName.getBytes("GBK"), "iso-8859-1") + "\"");
            ;

            try (ServletOutputStream out = response.getOutputStream();
                    FileInputStream in = new FileInputStream(file);
                    BufferedInputStream bufferStream = new BufferedInputStream(in, 1024 * 100);) {
                // 输入缓冲流
                int read = 0;
                byte[] bufferArea = new byte[1024 * 100];// 读写缓冲区

                // 在任何情况下，b[0] 到 b[off] 的元素以及 b[off+len] 到 b[b.length-1] 的元素都不会受到影响。这个是官方API给出的read方法说明，经典！
                while ((read = bufferStream.read(bufferArea, 0, 1024 * 100)) != -1) {
                    out.write(bufferArea, 0, read);
                }
                return true;
            } catch (Exception e) {
                log.warn("文件下载出错！", e);
                return false;
            }
        }
        return false;
    }

    /**
     * 
     * 获取服务器的公网ip,通过第三方网站chinaz
     * 
     * @Title getServerIpByChinaz
     * @return String
     * @throws IOException
     */
    public static String getServerIpByChinaz() throws IOException {
        String url = "http://ip.chinaz.com/";
        String str = getRemoteContent(url);
        String serverIp = "127.0.0.1";
        if (!"".equals(str) && null != str) {
            Matcher ma = PATTERN_IPFROM_CHINAZ.matcher(str);
            while (ma.find()) {
                serverIp = ma.group(1).replace("[<strong class=\"red\">", "").replace("</strong>] ", "");
            }
        }
        return serverIp;
    }

    /**
     * 
     * 获取服务器的公网ip,通过11315.com
     * 
     * @Title getServerIpBy11315
     * @return String
     * @throws IOException
     */
    public static String getServerIpBy11315() throws IOException {
        String serverIp = "127.0.0.1";
        String url = "http://www.11315.cn/getIp.jsp";
        String str = getRemoteContent(url);
        if (!"".equals(str) && null != str) {
            Matcher ma = PATTERN_IPFROM_11315.matcher(str);
            while (ma.find()) {
                serverIp = ma.group(1);
            }
        }
        return serverIp;
    }

    /**
     * 获取远程地址内容
     * 
     * @Title getRemoteContent
     * @author 吕凯
     * @date 2018年11月16日 上午9:16:49
     * @param url
     * @return String
     */
    public static String getRemoteContent(String url) {
        try {
            org.jsoup.nodes.Document doc = Jsoup.connect(url)
                    .userAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0").timeout(5000).get();
            return doc.text();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 
     * 获取服务器的公网ip,通过第三方网站
     * 
     * @Title getServerIpByIp138
     * @return String
     * @throws IOException
     */
    public static String getServerIpByIp138() throws IOException {
        String url = "http://www.ip138.com/ips1388.asp";
        String str = getRemoteContent(url);
        String serverIp = "127.0.0.1";
        if (!"".equals(str) && null != str) {
            Matcher ma = PATTERN_IPFROM_IP138.matcher(str);
            while (ma.find()) {
                serverIp = ma.group(1);
            }
        }
        return serverIp;
    }

    /**
     * 
     * 获取服务器的公网ip
     * 
     * @Title getServerIp
     * @return String
     * @throws IOException
     */
    public static String getServerIp() throws IOException {
        String ip = getServerIpBy11315();
        if (ip == null) {
            ip = "127.0.0.1";
        }
        if ("127.0.0.1".equals(ip)) {
            ip = getServerIpByIp138();
        }
        return ip;
    }

    public static void main(String[] args) {
        try {
            System.out.println(getServerIp());
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 
     * 获取服务器的机器名
     * 
     * @Title getMachineName
     * @return String
     */
    public static String getMachineName() {
        String machineName = "";
        InetAddress addr;
        try {
            addr = InetAddress.getLocalHost();
            machineName = addr.getHostName().toString();
        } catch (UnknownHostException e) {
            log.error("", e);
        }

        return machineName;
    }

    /**
     * 
     * 获取项目所在的目录
     * 
     * @Title getProjectDir
     * @return String
     */
    public static String getProjectDir() {
        String projectDir = "";
        projectDir = System.getProperty("user.dir").replace("bin", "");
        return projectDir;
    }

    /**
     * 
     * 添加浏览器缓存
     * 
     * @Title addBrowerCache
     * @author 吕凯
     * @date 2014-5-21 上午8:36:53
     * @param expiresSeconds
     *            缓存时间
     * @param response
     *            void
     */
    public static void addBrowerCache(int expiresSeconds, HttpServletResponse response) {
        Date createDate = new Date();
        response.setHeader("Cache-Control", "public, max-age=" + expiresSeconds);
        String gmtDateStr = DateUtil.getNowIeGMT(createDate);
        response.setHeader("Last-Modified", gmtDateStr);
        response.setHeader("date", gmtDateStr);
    }

    /**
     * 
     * 缓存是否可用
     * 
     * @Title canUseBrowerCache
     * @author 吕凯
     * @date 2014-5-21 上午8:35:06
     * @param expiresSeconds
     *            缓存时间
     * @param request
     * @return boolean
     */
    public static boolean canUseBrowerCache(int expiresSeconds, HttpServletRequest request) {
        String lastModifyDate = (String) request.getHeader("If-Modified-Since");
        Date lastMdate = null;
        if (lastModifyDate != null) {
            lastMdate = DateUtil.gmt2Date(lastModifyDate);
        }
        if (lastMdate != null && System.currentTimeMillis() <= lastMdate.getTime() + expiresSeconds * 1000L) {
            return true;
        }
        return false;
    }

    /**
     * 301跳转
     * 
     * @Title redirect301
     * @author 吕凯
     * @date 2020年11月10日 上午10:53:42
     * @param res
     * @param path
     * @throws IOException
     *             void
     */
    public static void redirect301(HttpServletResponse response, String path) {
        if (StringUtils.isNoneBlank(path)) {
            if (!path.startsWith("http") && !path.startsWith("ftp")) { // 相对路径
                if (!path.startsWith(Global.getProjectName())) { // 不带项目名则加上
                    path = Global.getProjectName() + path;
                }
            }
            response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
            response.setHeader("Location", path);
        } else {
            log.warn("跳转到的路径path为空");
        }
    }

    /**
     * 追加参数到路径
     * 
     * @Title appendQueryStr
     * @author 吕凯
     * @date 2020年11月10日 上午11:36:23
     * @param request
     * @param path
     *            void
     */
    public static String appendQueryStr2Path(HttpServletRequest request, String path) {
        if (StringUtils.isNotBlank(path)) {
            StringBuffer sb = new StringBuffer(path);
            if (StringUtils.isNoneBlank(request.getQueryString())) { // url后面的参数
                if (path.contains("?")) {
                    sb.append("&");
                } else {
                    sb.append("?");
                }
                sb.append(request.getQueryString());
            }
            return sb.toString();
        } else {
            log.warn("待处理的路径path为空");
        }
        return null;
    }

    /**
     * 获取302跳转的路径
     * 
     * @Title redirect
     * @author 吕凯
     * @date 2020年11月10日 上午10:54:24
     * @param res
     * @param path
     * @throws IOException
     *             void
     */
    public static String getRedirectPath(String path) {
        return REDIRECT + path; // 跳转搜索页面; 302临时跳转，改为301永久跳转
    }

    /**
     * 获取forward路径
     * 
     * @Title getForwordPath
     * @author 吕凯
     * @date 2020年11月10日 上午11:01:32
     * @param path
     * @return
     * @throws IOException
     *             String
     */
    public static String getForwordPath(String path) {
        return FORWORD + path; // 跳转搜索页面; 302临时跳转，改为301永久跳转
    }

    /**
     * 跳转404页面
     * 
     * @Title forward404
     * @author 吕凯
     * @date 2020年4月17日 下午2:27:17
     * @param message
     * @throws ServletException
     * @throws IOException
     *             void
     */
    public static void forward404(HttpServletRequest request, HttpServletResponse response, String message)
            throws ServletException, IOException {
        request.setAttribute("path", request.getServletPath());
        request.setAttribute("message", message);
        request.setAttribute("ip", WebUtil.getIpAddr(request));
//        request.setAttribute("error", message); //错误详情
//        return "error/error";
        forward(request, response, "error/error");
    }

    /**
     * 跳转页面
     * 
     * @Title forward
     * @author 吕凯
     * @date 2020年4月29日 下午5:03:17
     * @param page
     * @return
     * @throws ServletException
     * @throws IOException
     *             Object
     */
    public static void forward(HttpServletRequest request, HttpServletResponse response, String page) throws ServletException, IOException {
        if (page.startsWith("/")) {
            page = page.substring(1);
        }
        if (!page.endsWith(".jsp")) {
            page += ".jsp";
        }
        request.getRequestDispatcher("/WEB-INF/view/" + page).forward(request, response);
    }

    /**
     * 返回json格式
     * 
     * @Title sendJson
     * @author 吕凯
     * @date 2020年4月29日 下午5:03:06
     * @param result
     * @return
     * @throws ServletException
     * @throws IOException
     *             Object
     */
    public static void sendJson(HttpServletResponse response, Object result) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().print(JSONObject.toJSON(result));
    }
}
